﻿// demo_h2lib_python.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include "../h2lib_pybinder.h"

using namespace h2lib;
using namespace std;

void RegisterEntryModule(void);
static double AddNum(double a, double  b) {
    return a * 100 + b;
}
static std::function<std::string(int)> TestLambda(int a, const std::function<int(int)>&  funcExt) {
    return [a, funcExt](int b) 
    {
        return std::to_string(funcExt(a + b));
    };
}

struct Pos {
    Pos(int a = 0, int b = 0) :x(a), y(b) {
        printf("0x%p new pos\n", this);
    }
    ~Pos() {
        printf("0x%p delete pos\n", this);
    }
    int x;
    int y;
};
static std::shared_ptr<Pos> GenPos(int x, int y) {
    return shared_ptr<Pos>(new Pos(x, y));
}
static std::shared_ptr<Pos> ForkPos(const std::shared_ptr<Pos>& p) {
    std::shared_ptr<Pos> ret = p;
    ret->x = p->x + 1;
    ret->y = p->y + 1;
    return ret;
}
class Animal
{
public:
    static std::string PrintTypeName() { return typeid(Animal).name(); }
    Animal(std::string s = "") :name(s), color(0) {}
    Animal(std::string s, int c) :name(s), color(c) {}
    ~Animal() {

    }
    virtual void Go(int x, int y) {
        pos.x = x; pos.y = y;
    }
    virtual void Go(const Pos& p) {
        pos = p;
    }
    virtual  int Fly(int nHeight) {
        return 0;
    }
    void SetColor(int c) {
        color = c;
    }
    int GetColor() const {
        return color;
    }
    const std::string& GetName() const {
        return name;
    }
    void SetName(const char* s) {
        name = s;
    }
    const Pos& GetPos() const {
        return pos;
    }
    virtual const Animal* GetSelf() {
        return this;
    }
    bool IsSame(const Animal& p) const {
        return &p == this;
    }
    std::map<std::string, std::string> Dump() {
        std::map<std::string, std::string> ret;
        ret["name"] = name;
        ret["color"] = std::to_string(color);
        ret["pos"] = "[" + std::to_string(pos.x) + "," + std::to_string(pos.y) + "]";
        return ret;
    }
    int Touch(std::function<int(double)> cb) {
        return cb(66.99) + 100;
    }
    std::function<std::string(int)> GenFunc() {
        return [](int v)->std::string {
            std::string ret = "GenFunc:" + std::to_string(v);
            return ret;
        };
    }
public:
    std::string name;
    int color;
    Pos pos;
};

class  Bird :public Animal {
public:
    Bird(std::string strName = "") :Animal(strName), nT(1022){}
    ~Bird() {

    }
    virtual  int Fly(int nHeight) {
        return nHeight;
    }
    int nT;
};


#define  TestGuard(X, Y) printf("-------%s begin-----------\n", X);try {Y;}catch(std::exception& e_){printf("exception<%s>\n", e_.what());}\
        printf("-------%s end-----------\n", X);
void testBase()
{
    printf("sys.version=%s\n", H2_SCRIPT_BINDER.GetVar<std::string>("sys", "version").c_str());
    H2_SCRIPT_BINDER.SetVar("fftest", "global_var", "OhNice");
    printf("fftest.global_var=%s\n", H2_SCRIPT_BINDER.GetVar<std::string>("fftest", "global_var").c_str());
    printf("os.getcwd=%s\n", H2_SCRIPT_BINDER.Call<std::string>("os", "getcwd").c_str());
    printf("time.asctime=%s\n", H2_SCRIPT_BINDER.Call<std::string>("time", "asctime").c_str());
    int a1 = 100; float a2 = 3.14f; std::string a3 = "OhWell";
    H2_SCRIPT_BINDER.Call<void>("fftest", "testBase", a1, a2, a3);
    H2_SCRIPT_BINDER.Call<void>("fftest", "testmain", 100);
}
void testStl()
{
    std::vector<int> a1;a1.push_back(100);a1.push_back(200);
    std::list<std::string> a2; a2.push_back("Oh");a2.push_back("Nice");
    std::vector<std::list<std::string> > a3;a3.push_back(a2);

    H2_SCRIPT_BINDER.Call<bool>("fftest", "testStl", a1, a2, a3);

}

void test_returnStl()
{
    //typedef std::map<std::string, std::list<std::vector<int> > > ret_t;
    //ret_t val = H2_SCRIPT_BINDER.Call<ret_t>("fftest", "test_returnStl");
}

static int printVal(int a1, float a2, const std::string& a3, const std::vector<double>& a4)
{
    printf("%s[%d,%g,%s,%d]\n", __FUNCTION__, a1, a2, a3.c_str(), (int)a4.size());
    return 0;
}
struct OpsTest
{
    static std::list<int> returnStl()
    {
        std::list<int> ret;ret.push_back(1024);
        printf("%s\n", __FUNCTION__);
        return ret;
    }
};
void testRegisterBaseClass()
{
    H2_SCRIPT_BINDER.Call<void>("fftest", "testRegisterBaseClass");
};

class Foo
{
public:
    Foo(int v_) :nValue(v_)
    {
        printf("%s\n", __FUNCTION__);
    }
    virtual ~Foo()
    {
        printf("%s\n", __FUNCTION__);
    }
    int getValue() { return nValue; }
    void setValue(int v_) { nValue = v_; }
    void testStl(std::map<std::string, std::list<int> >& v_)
    {
        printf("%s\n", __FUNCTION__);
    }
    int nValue;
};

class Dumy : public Foo
{
public:
    Dumy(int v_) :Foo(v_)
    {
        printf("%s\n", __FUNCTION__);
    }
    ~Dumy()
    {
        printf("%s\n", __FUNCTION__);
    }
    void dump()
    {
        printf("%s\n", __FUNCTION__);
    }
};


static Foo* objTest(Dumy* p)
{
    printf("%s\n", __FUNCTION__);
    return p;
}


void testRegisterInheritClass()
{
    H2_SCRIPT_BINDER.Call<void>("fftest", "testRegisterInheritClass");
};

void testCppObjToPy()
{
    Dumy tmp_foo(2013);
    std::vector<Dumy*> vt;
    vt.push_back(&tmp_foo);
    H2_SCRIPT_BINDER.Call<void>("fftest", "testCppObjToPy", &tmp_foo);
    printf("testCppObjToPy changed nValue=%d\n", tmp_foo.nValue);
    H2_SCRIPT_BINDER.Call<void>("fftest", "testCppObjToPy2", vt);
}


void testPyClassLambda()
{
    /*
    PyObject* pFunc = H2_SCRIPT_BINDER.Call<PyObject*>("fftest", "testCppObjReturnPyLambda");
    std::vector<PyObject*> args;
    args.push_back(ScriptCppOps<int>::scriptFromCpp(1066));
    H2_SCRIPT_BINDER.callFuncByObjRet<void>(pFunc, args);
    Py_XDECREF(pFunc);

    PyObject* pobj = H2_SCRIPT_BINDER.Call<PyObject*>("fftest", "testCppObjReturnPyObj");
    Py_INCREF(pobj);
    std::vector<PyObject*> args1;
    args1.push_back(ScriptCppOps<int>::scriptFromCpp(1111));
    args1.push_back(ScriptCppOps<std::string>::scriptFromCpp("soNice"));
    H2_SCRIPT_BINDER.callMethodByObjRet<void>(pobj, "sayHi", args1);
    Py_XDECREF(pobj);
    */

}
int main()
{
    RegisterEntryModule();

    H2_SCRIPT_BINDER.Load("fftest");
    
    TestGuard("testBase", testBase());

    TestGuard("testStl", testStl());
    H2_SCRIPT_BINDER.Call<void>("fftest", "testRegFunction");

    TestGuard("testRegisterBaseClass", testRegisterBaseClass());

    TestGuard("testRegisterInheritClass", testRegisterInheritClass());

    TestGuard("testCppObjToPy", testCppObjToPy());

    TestGuard("testPyClassLambda", testPyClassLambda());

    std::cout << "Hello World!\n";
}
void RegisterEntryModule(void)
{
    H2_DEF_MODULE_BEGIN("ffext");

    H2_DEF_ITERFACE(&AddNum);
    H2_DEF_CLASS(Pos(int, int));
    H2_DEF_ITERFACE(&Pos::x);
    H2_DEF_ITERFACE(&Pos::y);
    H2_DEF_ITERFACE(&AddNum);
    H2_DEF_ITERFACE(&TestLambda);
    H2_DEF_ITERFACE(&GenPos);
    H2_DEF_ITERFACE(&ForkPos);

    H2_DEF_CLASS(Animal(const std::string&));
    H2_DEF_CLASS(Animal(const std::string&, int));

    H2_DEF_ITERFACE(&Animal::PrintTypeName);
    H2_DEF_ITERFACE((void(Animal::*)(int, int))(&Animal::Go));
    H2_DEF_ITERFACE((void(Animal::*)(const Pos&)) & Animal::Go);
    H2_DEF_ITERFACE(&Animal::GetColor);
    H2_DEF_ITERFACE(&Animal::SetColor);
    H2_DEF_ITERFACE(&Animal::SetName);
    H2_DEF_ITERFACE(&Animal::GetName);
    H2_DEF_ITERFACE(&Animal::GetPos);
    H2_DEF_ITERFACE(&Animal::color);
    H2_DEF_ITERFACE(&Animal::name);
    H2_DEF_ITERFACE(&Animal::GetSelf);
    H2_DEF_ITERFACE(&Animal::IsSame);
    H2_DEF_ITERFACE(&Animal::Dump);
    H2_DEF_ITERFACE(&Animal::Touch);


    H2_DEF_CLASS2(Bird(std::string), Animal);
    H2_DEF_ITERFACE(&Bird::Fly);


    H2_DEF_MODULE_END();//!一定要放模块定义的最后

    H2_DEF_MODULE_BEGIN("ffpython");

    H2_DEF_ITERFACE(&printVal);
    H2_DEF_ITERFACE(&OpsTest::returnStl);
    H2_DEF_CLASS(Foo(int));
    H2_DEF_ITERFACE(&Foo::getValue);
    H2_DEF_ITERFACE(&Foo::setValue);
    H2_DEF_ITERFACE(&Foo::testStl);
    H2_DEF_ITERFACE(&Foo::nValue);

    H2_DEF_CLASS2(Dumy(int), Foo);
    H2_DEF_ITERFACE(&Dumy::dump);
    H2_DEF_ITERFACE(&objTest);

    H2_DEF_MODULE_END();//!一定要放模块定义的最后
    
}


// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
